package me.aartikov.alligator.helpers;


import me.aartikov.alligator.AbilityResult;
import me.aartikov.alligator.destinations.AbilityDestination;
import me.aartikov.alligator.destinations.FragmentDestination;
import me.aartikov.alligator.exceptions.InvalidScreenResultException;
import me.aartikov.alligator.exceptions.NavigationException;
import me.aartikov.alligator.exceptions.ScreenRegistrationException;
import me.aartikov.alligator.listeners.ScreenResultListener;
import me.aartikov.alligator.navigationfactories.NavigationFactory;
import me.aartikov.alligator.Screen;
import me.aartikov.alligator.ScreenResult;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;

/**
 * Helps to return a screen result from activities and fragments.
 */
public class ScreenResultHelper {
    public static final String KEY_REQUEST_CODE = "me.aartikov.alligator.KEY_REQUEST_CODE";
    public static final String KEY_RESULT_CODE = "me.aartikov.alligator.KEY_RESULT_CODE";

    private NavigationFactory mNavigationFactory;

    public ScreenResultHelper(NavigationFactory navigationFactory) {
        mNavigationFactory = navigationFactory;
    }

    public void setActivityResult(Ability activity, ScreenResult screenResult) throws NavigationException {
        AbilityDestination activityDestination = getAndValidateActivityDestination(activity, screenResult);
        AbilityResult activityResult = activityDestination.createActivityResult(screenResult);
        activity.setResult(activityResult.getResultCode(), activityResult.getIntent());
        activity.terminateAbility();
    }

    public void setResultToIntent(Intent intent, Ability activity, ScreenResult screenResult) throws NavigationException {
        AbilityDestination activityDestination = getAndValidateActivityDestination(activity, screenResult);
        AbilityResult activityResult = activityDestination.createActivityResult(screenResult);
        intent.setParam(KEY_REQUEST_CODE, activityDestination.getRequestCode());
        intent.setParam(KEY_RESULT_CODE, activityResult.getResultCode());

        Intent resultIntent = activityResult.getIntent();
        if (resultIntent != null) {
            intent.replaceParams(resultIntent);
//            intent.putExtras(resultIntent);
        }
    }


    private AbilityDestination getAndValidateActivityDestination(Ability activity, ScreenResult screenResult) throws NavigationException {
        Class<? extends Screen> screenClass = mNavigationFactory.getScreenClass(activity);
        if (screenClass == null) {
            throw new ScreenRegistrationException("Failed to get a screen class for " + activity.getClass().getSimpleName());
        }

        AbilityDestination activityDestination = (AbilityDestination) mNavigationFactory.getDestination(screenClass);
        if (activityDestination == null) {
            throw new ScreenRegistrationException("Failed to get a destination for " + screenClass.getSimpleName());
        }

        if (activityDestination.getScreenResultClass() == null) {
            throw new InvalidScreenResultException("Screen " + screenClass.getSimpleName() + " can't return a result.");
        }

        Class<? extends ScreenResult> supportedScreenResultClass = activityDestination.getScreenResultClass();
        if (!supportedScreenResultClass.isAssignableFrom(screenResult.getClass())) {
            throw new InvalidScreenResultException("Screen " + screenClass.getSimpleName() + " can't return a result of class " + screenResult.getClass().getCanonicalName() +
                    ". It returns a result of class " + supportedScreenResultClass.getCanonicalName());
        }

        return activityDestination;
    }

    public void callScreenResultListener(MiFraction fragment, ScreenResult screenResult, ScreenResultListener screenResultListener) throws NavigationException {
        Class<? extends Screen> screenClass = mNavigationFactory.getScreenClass(fragment);
        if (screenClass == null) {
            throw new ScreenRegistrationException("Failed to get a screen class for " + fragment.getClass().getSimpleName());
        }

        FragmentDestination fragmentDestination = (FragmentDestination) mNavigationFactory.getDestination(screenClass);
        if (fragmentDestination == null) {
            throw new ScreenRegistrationException("Failed to get a destination for " + screenClass.getSimpleName());
        }

        Class<? extends ScreenResult> supportedScreenResultClass = fragmentDestination.getScreenResultClass();
        if (supportedScreenResultClass == null) {
            if (screenResult == null) {
                return;
            } else {
                throw new InvalidScreenResultException("Screen " + screenClass.getSimpleName() + " can't return a result.");
            }
        }

        if (screenResult != null && !supportedScreenResultClass.isAssignableFrom(screenResult.getClass())) {
            throw new InvalidScreenResultException("Screen " + screenClass.getSimpleName() + " can't return a result of class " + screenResult.getClass().getCanonicalName() +
                    ". It returns a result of class " + supportedScreenResultClass.getCanonicalName());
        }

        screenResultListener.onScreenResult(screenClass, screenResult);
    }


    //TODO 暂无替换方式 无DialogFragment对应
//    public void callScreenResultListener(DialogFragment dialogFragment, ScreenResult screenResult, ScreenResultListener screenResultListener) throws NavigationException {
//        Class<? extends Screen> screenClass = mNavigationFactory.getScreenClass(dialogFragment);
//        if (screenClass == null) {
//            throw new ScreenRegistrationException("Failed to get a screen class for " + dialogFragment.getClass().getSimpleName());
//        }
//
//        DialogFragmentDestination dialogFragmentDestination = (DialogFragmentDestination) mNavigationFactory.getDestination(screenClass);
//        if (dialogFragmentDestination == null) {
//            throw new ScreenRegistrationException("Failed to get a destination for " + screenClass.getSimpleName());
//        }
//
//        Class<? extends ScreenResult> supportedScreenResultClass = dialogFragmentDestination.getScreenResultClass();
//        if (supportedScreenResultClass == null) {
//            if (screenResult == null) {
//                return;
//            } else {
//                throw new InvalidScreenResultException("Screen " + screenClass.getSimpleName() + " can't return a result.");
//            }
//        }
//
//        if (screenResult != null && !supportedScreenResultClass.isAssignableFrom(screenResult.getClass())) {
//            throw new InvalidScreenResultException("Screen " + screenClass.getSimpleName() + " can't return a result of class " + screenResult.getClass().getCanonicalName() +
//                    ". It returns a result of class " + supportedScreenResultClass.getCanonicalName());
//        }
//
//        screenResultListener.onScreenResult(screenClass, screenResult);
//    }
}
